package abel.wlmr.model.type;

import abel.util.StdBcdNumber;
import abel.wlmr.model.WlmrException;
import io.netty.buffer.ByteBuf;

/**
 * B.5.12.2.5.5 ERC12： 远传表时间超差
 * 事件记录的数据格式见表 B.189。
 * 
 * 表B.189 远传表时间超差数据单元格式
 * 数据内容
 * 数据格式 字节数
 * D7/D15 D6/D14 D5/D13 D4/D12 D3/D11 D2/D10 D1/D9 D0/D8
 * ERC=12 BIN 1
 * 长度 Le BIN 1
 * 发生时间：分时日月年 见附录 C.15 5
 * D15：起/止标志 D14～D12：备用 D11～D0： pn（测量点号 1～2048） BIN 2
 * 
 * @author Abel
 *
 */
public class Erc12Body extends ErcBaseBody {

    private static final short FIXED_LENGTH = (short) (5 + 2);

    /**
     * 发生时间：分时日月年 见附录 C.15 5
     */
    private StdBcdNumber occurTime;

    private byte startStop;

    private short pn;

    public Erc12Body(short guessedLen) {
        super(guessedLen, (short) 12, FIXED_LENGTH);
    }

    public Erc12Body() {
        this((short) -1);
    }

    /* (non-Javadoc)
     * @see abel.wlmr.model.AppUnitBody#getFinalLen()
     */
    @Override
    public short getFinalLen() {
        return MIN_LENGTH + FIXED_LENGTH;
    }

    /* (non-Javadoc)
     * @see abel.wlmr.model.ErcBaseBody#appendBuf(io.netty.buffer.ByteBuf)
     */
    @Override
    public ByteBuf appendBuf(ByteBuf buf) {
        if (occurTime == null || occurTime.length() != 5) {
            throw new IllegalArgumentException("occur time should be C.15 format");
        }

        if (pn < 1 || pn > 2048) {
            throw new IllegalArgumentException("pn should be [1,2048]");
        }

        if (startStop < 0 || startStop > 1) {
            throw new IllegalArgumentException("start stop flag should be 0/1");
        }

        // append erc & le.
        buf.writeByte(erc);
        buf.writeByte(le);

        buf.writeBytes(occurTime.toBytes());
        buf.writeShortLE(startStop << 15 | pn);

        return buf;
    }

    /* (non-Javadoc)
     * @see abel.wlmr.model.ErcBaseBody#parseBuf(io.netty.buffer.ByteBuf)
     */
    @Override
    public int parseBuf(ByteBuf buf) throws WlmrException {
        if (checkBuffer(buf) < 0) {
            return -1;
        }

        buf.skipBytes(MIN_LENGTH);

        occurTime = new StdBcdNumber();
        occurTime.populateBytes(buf, 5);

        int flag = buf.readShortLE();
        pn = (short) (flag & 0x0FFF);
        startStop = (byte) ((flag >> 15) & 1);

        return MIN_LENGTH + FIXED_LENGTH;
    }

    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return String.format("{occurTime:%s, startStop:%s, pn:%s}", occurTime, startStop, pn);
    }

    /**
     * 发生时间：分时日月年 见附录 C.15 5
     * 
     * @return the occurTime
     */
    public StdBcdNumber getOccurTime() {
        return occurTime;
    }

    /**
     * 发生时间：分时日月年 见附录 C.15 5
     * 
     * @param occurTime
     *            the occurTime to set
     */
    public void setOccurTime(StdBcdNumber occurTime) {
        if (occurTime == null || occurTime.length() != 5) {
            throw new IllegalArgumentException("occur time should be C.15 format");
        }

        // may throw IAE
        occurTime.toMeterC15Joda();

        this.occurTime = occurTime;
    }

    /**
     * @return the startStop
     */
    public byte getStartStop() {
        return startStop;
    }

    /**
     * @param startStop
     *            the startStop to set
     */
    public void setStartStop(byte startStop) {
        if (startStop < 0 || startStop > 1) {
            throw new IllegalArgumentException("start stop flag should be 0/1");
        }

        this.startStop = startStop;
    }

    /**
     * @return the pn
     */
    public short getPn() {
        return pn;
    }

    /**
     * @param pn
     *            the pn to set
     */
    public void setPn(short pn) {
        if (pn < 1 || pn > 2048) {
            throw new IllegalArgumentException("pn should be [1,2048]");
        }

        this.pn = pn;
    }

}
